package com.sinder.campus_prophet.service.jwgl.impl;

import cc.lyceum.api.thxy.jwgl.ThxyJwgl;
import cc.lyceum.api.thxy.jwgl.pojo.Curriculum;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sinder.campus_prophet.core.enums.TimeBar;
import com.sinder.campus_prophet.core.global.ResponseMessage;
import com.sinder.campus_prophet.entity.jwgl.TbSchedule;
import com.sinder.campus_prophet.entity.jwgl.TbTerm;
import com.sinder.campus_prophet.exception.JwglException;
import com.sinder.campus_prophet.mapper.general.TbWxUserMapper;
import com.sinder.campus_prophet.mapper.jwgl.TbJwglInfoMapper;
import com.sinder.campus_prophet.mapper.jwgl.TbTermMapper;
import com.sinder.campus_prophet.service.jwgl.TbScheduleService;
import com.sinder.campus_prophet.mapper.jwgl.TbScheduleMapper;
import com.sinder.campus_prophet.service.jwgl.bean.bo.TimeBarBo;
import com.sinder.campus_prophet.service.jwgl.bean.dto.*;
import com.sinder.campus_prophet.service.jwgl.bean.vo.JwglInfoVo;
import com.sinder.campus_prophet.service.jwgl.bean.vo.ScheduleVo;
import com.sinder.campus_prophet.utils.CurrentXqCodeUtils;
import com.sinder.campus_prophet.utils.RandomColorUtils;
import com.sinder.campus_prophet.utils.WeekUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.io.UnsupportedEncodingException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
* @author AS
* @description 针对表【tb_schedule(课表数据)】的数据库操作Service实现
* @createDate 2023-03-15 23:13:21
*/
@Service
@Slf4j
public class TbScheduleServiceImpl extends ServiceImpl<TbScheduleMapper, TbSchedule>
    implements TbScheduleService{

    private final TbScheduleMapper scheduleMapper;

    private final TbWxUserMapper wxUserMapper;

    private final TbJwglInfoMapper jwglInfoMapper;

    private final TbTermMapper tbTermMapper;

    public TbScheduleServiceImpl(TbScheduleMapper scheduleMapper, TbWxUserMapper wxUserMapper, TbJwglInfoMapper jwglInfoMapper, TbTermMapper tbTermMapper) {
        this.scheduleMapper = scheduleMapper;
        this.wxUserMapper = wxUserMapper;
        this.jwglInfoMapper = jwglInfoMapper;
        this.tbTermMapper = tbTermMapper;
    }

    /**
     * 返回本学期本周的周次
     * @return
     */
    @Override
    public ResponseMessage getWeekList() {
        // 返回当前周以及周数，查询参数
        Integer[] paramArr = new Integer[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}; // 预计只有18周的课表
        Map<String, Object> weekMap = new HashMap<>();
        weekMap.put("weekParam", paramArr);
        try {
            Date startDate = new SimpleDateFormat("yyyy-MM-dd").parse(tbTermMapper.selectById(1).getStartTime());
            // 获取当前周次
            int currentWeekNumber = WeekUtils.getCurrentWeekNumber(startDate, new Date());
            weekMap.put("currentWeek", currentWeekNumber);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
        return ResponseMessage.createBySuccess(weekMap);
    }

    /**
     * 课表查询(个人) 根据u-code+时间查询 包括共享课表人的课表信息
     * @param scheduleDto
     * @return
     */
    @Override
    public ResponseMessage getScheduleList(ScheduleDto scheduleDto) {
        // 查询自己的课表数据
        List<ScheduleVo> scheduleList = scheduleMapper.getScheduleList(scheduleDto);
        if (scheduleList.size() == 0) {
            return ResponseMessage.createByErrorMessage("暂无数据，请移步同步数据");
        }
        // 构造侧边时间菜单
        List<TimeBarBo> timeBarBoList = new ArrayList<>();
        for (int i = 0; i <= (TimeBar.START_TIME.length - 1); i++) {
            TimeBarBo timeBarBo = new TimeBarBo();
            timeBarBo.setIndexOf(i + 1);
            timeBarBo.setTimeStart(TimeBar.START_TIME[i]);
            timeBarBo.setTimeEnd(TimeBar.END_TIME[i]);
            timeBarBoList.add(timeBarBo);
        }
        // 响应数据 TreeMap:按键值排序
        Map<String, List<ScheduleVo>> stringListMap = new TreeMap<>();
        // 分组 0102，0304，0506...
        Map<String, List<ScheduleVo>> map =
                scheduleList.stream()
                .collect(Collectors.groupingBy(ScheduleVo::getJcdm));

        map.forEach((key, value) -> {
            // 初始化(周次)容器
            List<ScheduleVo> list = new ArrayList<>();
            for (int i = 0; i < 7; i++) {
                ScheduleVo scheduleVo = new ScheduleVo();
                // 默认没课
                scheduleVo.setType(false);
                list.add(scheduleVo);
            }
            value.forEach(item -> {
                // item.setType(true); // 有课
//                if (list.get(Integer.parseInt(item.getXq()) - 1).getType()) {
//                    // 已存在课程 -- 有的课程会重叠 -- 需要合并
//                } else {
//                    list.set(Integer.parseInt(item.getXq()) - 1, item);
//                }
                list.set(Integer.parseInt(item.getXq()) - 1, item);
            });
            stringListMap.put(key, list);
        });
        // 检查有哪个key不存在的
        Arrays.stream(TimeBar.MAPS).forEach(item -> {
            if (!stringListMap.containsKey(item[0])) {
                // 不存在则初始化一个值
                List<ScheduleVo> list = new ArrayList<>();
                for (int i = 0; i < 7; i++) {
                    ScheduleVo scheduleVo = new ScheduleVo();
                    scheduleVo.setType(false);
                    list.add(scheduleVo);
                }
                stringListMap.put(item[1], list);
            } else {
                // 替换key值
                stringListMap.put(item[1], stringListMap.remove(item[0]));
            }
        });
        // 判断周六日是否有课，周六日无课则不显示周六日
        boolean isKc = false;
        for (Map.Entry<String, List<ScheduleVo>> i : stringListMap.entrySet()) {
            if (i.getValue().get(5).getType() || i.getValue().get(6).getType()) {
                // 存在任意一节课，直接跳出
                isKc = true;
                break;
            }
        }
        if (!isKc) {
            // 无课则移除
            for (Map.Entry<String, List<ScheduleVo>> i : stringListMap.entrySet()) {
                i.getValue().remove(i.getValue().size() - 1);
                i.getValue().remove(i.getValue().size() - 1);
            }
        }
        // 封装响应数据
        Map<String, Object> result = new HashMap<>();
        result.put("time", timeBarBoList);
        result.put("schedule", stringListMap);
        result.put("isKc", isKc);
        return ResponseMessage.createBySuccess("本周课表", result);
    }

    /**
     * 获取今日课表数据
     * @param scheduleTodayDto
     * @return
     */
    @Override
    public ResponseMessage getTodayScheduleList(ScheduleTodayDto scheduleTodayDto) {
        // 本学期开始时间
        String startDateStr = tbTermMapper.selectById(1).getStartTime();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Date startDate = null;
        try {
            startDate = dateFormat.parse(startDateStr);
            // 获取当前周次和星期
            int currentWeekNumber = WeekUtils.getCurrentWeekNumber(startDate, new Date());
            int currentDayOfWeek = WeekUtils.getCurrentDayOfWeek(new Date());
//            log.info("当前时间是第 " + currentWeekNumber + " 周，周" + currentDayOfWeek);
            // 查询数据
            QueryWrapper<TbSchedule> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("wx_open_id", scheduleTodayDto.getOpenId());
            queryWrapper.eq("zc", currentWeekNumber);
            queryWrapper.eq("xq", currentDayOfWeek);
            queryWrapper.orderByAsc("jcdm"); // 升序

            List<TbSchedule> selectList = scheduleMapper.selectList(queryWrapper);
            if (selectList.size() == 0) {
                return ResponseMessage.createBySuccessMessage("今日无课");
            }
            List<ScheduleVo> scheduleVoList = selectList.stream().map(item -> {
                ScheduleVo scheduleVo = new ScheduleVo();
                BeanUtils.copyProperties(item, scheduleVo);
                scheduleVo.setKccxsj(TimeBar.JCDM_CODE.get(scheduleVo.getJcdm()));
                scheduleVo.setJxcdmc(StringUtils.substringBefore(scheduleVo.getJxcdmc(), "("));
                return scheduleVo;
            }).collect(Collectors.toList());
            return ResponseMessage.createBySuccess("今日课表", scheduleVoList);
        } catch (ParseException e) {
            e.printStackTrace();
            throw new RuntimeException("时间参数转换异常[ParseException]：" + e.getMessage());
        }
    }

    /**
     * 同步课表数据 单独同步教务系统课表
     * @param scheduleSynDto
     * @return
     */
    @Async("taskExecutor")
    @Override
    public ResponseMessage synScheduleData(ScheduleSynDto scheduleSynDto, ThxyJwgl jwgl) {
        log.info(Thread.currentThread().getThreadGroup() + "--------" + Thread.currentThread().getName());
        String openId = scheduleSynDto.getOpenId();
        // 数据同步开始时间
        long start = System.currentTimeMillis();
        // 获取用户标识
        String userCode = wxUserMapper.getUserCode(openId);
        String xqCode = CurrentXqCodeUtils.getCurrentXqCode();
        try {
            // 4：获取课表 按学期代码和周数全量同步(正常一学期20周) -- 数据同步前先清空用户旧数据(只保留一个学期课表)
            // 获取本学期代码值
            QueryWrapper<TbSchedule> scheduleDelQuery = new QueryWrapper<>();
            scheduleDelQuery.eq("wx_open_id", openId);
            int schDelRow = scheduleMapper.delete(scheduleDelQuery);
            log.info("----已清空用户openId为：{}的课表信息{}条数据，正在同步新数据----", openId, schDelRow);
            for (int i = 1; i <= 20; i++) {
                List<Curriculum> curriculumList = jwgl.getSelfCurriculum(xqCode, String.valueOf(i));
                if (curriculumList.size() == 0) {
                    continue;
                }
                List<TbSchedule> scheduleList = curriculumList.stream().map(item -> {
                    TbSchedule schedule = new TbSchedule();
                    BeanUtils.copyProperties(item, schedule);
                    schedule.setType(true); // 设定为有课，默认值
                    schedule.setWxOpenId(openId);
                    // 添加用户标识
                    schedule.setUserCode(userCode);
                    schedule.setSynTime(new Date());
                    schedule.setBgColor(RandomColorUtils.getColor());
                    return schedule;
                }).collect(Collectors.toList());
                // 批量入库
                scheduleMapper.insertBatch(scheduleList);
            }
        } finally {
            // 结束后退出登录
            if (jwgl != null) {
                jwgl.logout();
            }
        }
        // 数据同步结束时间
        long end = System.currentTimeMillis();
        log.info("用户{}的{}学年课表数据已同步，共耗时：{}s", openId, xqCode, (end-start) / 1000);
        return ResponseMessage.createBySuccessMessage("个人课表数据已同步，共耗时：" + (end-start) / 1000 + "s");
    }

    /**
     * 添加课程(自定义)
     * @param scheduleAddDto
     * @return
     */
    @Override
    public ResponseMessage addScheduleByOpenId(ScheduleAddDto scheduleAddDto) {
        TbSchedule schedule = new TbSchedule();
        BeanUtils.copyProperties(scheduleAddDto, schedule);
        schedule.setJcdm(TimeBar.JCDM_MAP.get(scheduleAddDto.getJcdm()));
        // 设置一个空值
        schedule.setSknrjj("");
        schedule.setSynTime(new Date());
        schedule.setType(true);
        schedule.setBgColor(RandomColorUtils.getColor());

        // 新增
        int addRow = scheduleMapper.insert(schedule);

        if (addRow <= 0) {
            return ResponseMessage.createByErrorMessage("新增课程异常");
        }
        return ResponseMessage.createBySuccessMessage("新增课表成功");
    }

    /**
     * 移除课程(自定义)
     * 移除课程为逻辑删除
     * 修改type为false
     * @param scheduleDelDto
     * @return
     */
    @Override
    public ResponseMessage delScheduleById(ScheduleDelDto scheduleDelDto) {
        TbSchedule schedule = new TbSchedule();
        schedule.setScheduleId(scheduleDelDto.getScheduleId());
        schedule.setType(false); // 移除课表
        schedule.setBgColor("#b5b5b5"); // 移除的课程设置背景颜色为灰色
        int delRow = scheduleMapper.updateById(schedule);
        if (delRow <= 0) {
            return ResponseMessage.createByErrorMessage("移除课程异常");
        }
        return ResponseMessage.createBySuccessMessage("课程已移除");
    }

    /**
     * 恢复课程
     * @param scheduleDelDto
     * @return
     */
    @Override
    public ResponseMessage restoreScheduleById(ScheduleDelDto scheduleDelDto) {
        TbSchedule schedule = new TbSchedule();
        schedule.setScheduleId(scheduleDelDto.getScheduleId());
        schedule.setType(true); // 移除课表
        schedule.setBgColor(RandomColorUtils.getColor()); // 移除的课程设置背景颜色为灰色
        int delRow = scheduleMapper.updateById(schedule);
        if (delRow <= 0) {
            return ResponseMessage.createByErrorMessage("恢复课程异常");
        }
        return ResponseMessage.createBySuccessMessage("课程已恢复");
    }
}




